1. Хэрэгтэй сангууд:

packages = c('tidyverse', 'kableExtra', 'plotly', 'lubridate', 'pacman')

for (p in packages){
  if (!require(p,character.only = T)){
    install.packages(p)
  }
  library(p,character.only = T)
}
p_load(tidyverse,lubridate,showtext)
showtext_auto()
font_add_google("Bebas Neue", "Bebas Neue")

2. Өгөгдөл уншиж авах:

df <- read_csv('dataset/netflix_titles.csv')
Rows: 8807 Columns: 12── Column specification ───────────────────────────────────────────────────────
Delimiter: ","
chr (11): show_id, type, title, director, cast, country, date_added, rating...
dbl  (1): release_year
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

3. Өгөгдөл боловсруулалт

3.1 Өгөгдөл багсгалт

# Хэрэгцээгүй утгуудыг цэвэрлэх явц
df <- tibble::as_tibble(df) %>% 
  select(-c( description))
# дата шалтгалт
kable(df[1:10,]) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  scroll_box(width = "100%", height = "500px")
show_id type title director cast country date_added release_year rating duration listed_in
s1 Movie Dick Johnson Is Dead Kirsten Johnson NA United States September 25, 2021 2020 PG-13 90 min Documentaries
s2 TV Show Blood & Water NA Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Molaba, Dillon Windvogel, Natasha Thahane, Arno Greeff, Xolile Tshabalala, Getmore Sithole, Cindy Mahlangu, Ryle De Morny, Greteli Fincham, Sello Maake Ka-Ncube, Odwa Gwanya, Mekaila Mathys, Sandi Schultz, Duane Williams, Shamilla Miller, Patrick Mofokeng South Africa September 24, 2021 2021 TV-MA 2 Seasons International TV Shows, TV Dramas, TV Mysteries
s3 TV Show Ganglands Julien Leclercq Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabiha Akkari, Sofia Lesaffre, Salim Kechiouche, Noureddine Farihi, Geert Van Rampelberg, Bakary Diombera NA September 24, 2021 2021 TV-MA 1 Season Crime TV Shows, International TV Shows, TV Action & Adventure
s4 TV Show Jailbirds New Orleans NA NA NA September 24, 2021 2021 TV-MA 1 Season Docuseries, Reality TV
s5 TV Show Kota Factory NA Mayur More, Jitendra Kumar, Ranjan Raj, Alam Khan, Ahsaas Channa, Revathi Pillai, Urvi Singh, Arun Kumar India September 24, 2021 2021 TV-MA 2 Seasons International TV Shows, Romantic TV Shows, TV Comedies
s6 TV Show Midnight Mass Mike Flanagan Kate Siegel, Zach Gilford, Hamish Linklater, Henry Thomas, Kristin Lehman, Samantha Sloyan, Igby Rigney, Rahul Kohli, Annarah Cymone, Annabeth Gish, Alex Essoe, Rahul Abburi, Matt Biedel, Michael Trucco, Crystal Balint, Louis Oliver NA September 24, 2021 2021 TV-MA 1 Season TV Dramas, TV Horror, TV Mysteries
s7 Movie My Little Pony: A New Generation Robert Cullen, José Luis Ucha Vanessa Hudgens, Kimiko Glenn, James Marsden, Sofia Carson, Liza Koshy, Ken Jeong, Elizabeth Perkins, Jane Krakowski, Michael McKean, Phil LaMarr NA September 24, 2021 2021 PG 91 min Children & Family Movies
s8 Movie Sankofa Haile Gerima Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri United States, Ghana, Burkina Faso, United Kingdom, Germany, Ethiopia September 24, 2021 1993 TV-MA 125 min Dramas, Independent Movies, International Movies
s9 TV Show The Great British Baking Show Andy Devonshire Mel Giedroyc, Sue Perkins, Mary Berry, Paul Hollywood United Kingdom September 24, 2021 2021 TV-14 9 Seasons British TV Shows, Reality TV
s10 Movie The Starling Theodore Melfi Melissa McCarthy, Chris O'Dowd, Kevin Kline, Timothy Olyphant, Daveed Diggs, Skyler Gisondo, Laura Harrier, Rosalind Chao, Kimberly Quinn, Loretta Devine, Ravi Kapoor United States September 24, 2021 2021 PG-13 104 min Comedies, Dramas

3.2 Хоосон утгуудыг цэвэрлэх, цэгцлэх

# Хоосон утгатай өгөгдлийг илрүүлэх
data.frame(var = c(colnames(df)), 
           missing = sapply(df, function(x) sum(is.na(x))), row.names = NULL) %>%
  mutate(missing = cell_spec(missing, "html", 
                             color = ifelse(missing > 0, 'red', 'black'))) %>% 
  rename(`Баганын нэр` = var, `Хоосон утгын тоо` = missing) %>%
  kable(format = "html", escape = F, align = c("l", "c")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F)
Баганын нэр Хоосон утгын тоо
show_id 0
type 0
title 0
director 2634
cast 825
country 831
date_added 10
release_year 0
rating 4
duration 3
listed_in 0
# Мод олох функч
getmode <- function(v) {
   uniqv <- unique(v)
   uniqv[which.max(tabulate(match(v, uniqv)))]
}
df$rating[is.na(df$rating)] <- getmode(df$rating)

# давхардсан өгөгдөлүүдийг цэвэхлэх -> title, country, type болон release_year
df <- distinct(df, type, title, country, release_year, show_id, listed_in, .keep_all = T)

3.3 Он сарын порматын өөрчлөлт

# он сарын утгын порматын өөрчлөлт
df$date_added <- as.Date(df$date_added, format = "%B %d, %Y")
# он сарын порматын шалгалт
kable(df[1:10,]) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>% 
  column_spec(6, color = 'red', bold = T) %>% 
  scroll_box(width = "100%", height = "352px")
show_id type title director cast country date_added release_year rating duration listed_in
s1 Movie Dick Johnson Is Dead Kirsten Johnson NA United States 2021-09-25 2020 PG-13 90 min Documentaries
s2 TV Show Blood & Water NA Ama Qamata, Khosi Ngema, Gail Mabalane, Thabang Molaba, Dillon Windvogel, Natasha Thahane, Arno Greeff, Xolile Tshabalala, Getmore Sithole, Cindy Mahlangu, Ryle De Morny, Greteli Fincham, Sello Maake Ka-Ncube, Odwa Gwanya, Mekaila Mathys, Sandi Schultz, Duane Williams, Shamilla Miller, Patrick Mofokeng South Africa 2021-09-24 2021 TV-MA 2 Seasons International TV Shows, TV Dramas, TV Mysteries
s3 TV Show Ganglands Julien Leclercq Sami Bouajila, Tracy Gotoas, Samuel Jouy, Nabiha Akkari, Sofia Lesaffre, Salim Kechiouche, Noureddine Farihi, Geert Van Rampelberg, Bakary Diombera NA 2021-09-24 2021 TV-MA 1 Season Crime TV Shows, International TV Shows, TV Action & Adventure
s4 TV Show Jailbirds New Orleans NA NA NA 2021-09-24 2021 TV-MA 1 Season Docuseries, Reality TV
s5 TV Show Kota Factory NA Mayur More, Jitendra Kumar, Ranjan Raj, Alam Khan, Ahsaas Channa, Revathi Pillai, Urvi Singh, Arun Kumar India 2021-09-24 2021 TV-MA 2 Seasons International TV Shows, Romantic TV Shows, TV Comedies
s6 TV Show Midnight Mass Mike Flanagan Kate Siegel, Zach Gilford, Hamish Linklater, Henry Thomas, Kristin Lehman, Samantha Sloyan, Igby Rigney, Rahul Kohli, Annarah Cymone, Annabeth Gish, Alex Essoe, Rahul Abburi, Matt Biedel, Michael Trucco, Crystal Balint, Louis Oliver NA 2021-09-24 2021 TV-MA 1 Season TV Dramas, TV Horror, TV Mysteries
s7 Movie My Little Pony: A New Generation Robert Cullen, José Luis Ucha Vanessa Hudgens, Kimiko Glenn, James Marsden, Sofia Carson, Liza Koshy, Ken Jeong, Elizabeth Perkins, Jane Krakowski, Michael McKean, Phil LaMarr NA 2021-09-24 2021 PG 91 min Children & Family Movies
s8 Movie Sankofa Haile Gerima Kofi Ghanaba, Oyafunmike Ogunlano, Alexandra Duah, Nick Medley, Mutabaruka, Afemo Omilami, Reggie Carter, Mzuri United States, Ghana, Burkina Faso, United Kingdom, Germany, Ethiopia 2021-09-24 1993 TV-MA 125 min Dramas, Independent Movies, International Movies
s9 TV Show The Great British Baking Show Andy Devonshire Mel Giedroyc, Sue Perkins, Mary Berry, Paul Hollywood United Kingdom 2021-09-24 2021 TV-14 9 Seasons British TV Shows, Reality TV
s10 Movie The Starling Theodore Melfi Melissa McCarthy, Chris O'Dowd, Kevin Kline, Timothy Olyphant, Daveed Diggs, Skyler Gisondo, Laura Harrier, Rosalind Chao, Kimberly Quinn, Loretta Devine, Ravi Kapoor United States 2021-09-24 2021 PG-13 104 min Comedies, Dramas

4. Дүрслэх эцсийн алхамууд ба ойлголтууд

4.1 Агуулгын төрлөөр эзлэх хувь

content_by_type <- df %>% group_by(type) %>% 
  summarise(count = n())

plot_ly(content_by_type, labels = ~type, values = ~count, 
        type = 'pie', marker = list(colors = c("#bd3939", "#399ba3"))) %>% 
  layout(xaxis = list(showgrid = F, zeroline = F, showticklabels = F),
         yaxis = list(showgrid = F, zeroline = F, showticklabels = F),
         title = "Агуулгын төрлөөр эзлэх хувь", margin = list(t = 54),
         legend = list(x = 100, y = 0.5))

4.2 Үйлдвэрлэсэн агуулгын хэмжээгээр эхний 12 улс


s <- strsplit(df$country, split = ", ")
cntry_split <- data.frame(type = rep(df$type, sapply(s, length)), country = unlist(s))
cntry_split$country <- as.character(gsub(",","", cntry_split$country))

amount_by_country <- na.omit(cntry_split) %>%
  group_by(country, type) %>%
  summarise(count = n())
`summarise()` has grouped output by 'country'. You can override using the `.groups` argument.
w <- reshape(data = data.frame(amount_by_country), 
             idvar = "country",
             v.names = "count",
             timevar = "type",
             direction = "wide") %>% 
  arrange(desc(count.Movie)) %>% top_n(12)
Selecting by count.TV Show
names(w)[2] <- "count_movie"
names(w)[3] <- "count_tv_show"
w <- w[order(desc(w$count_movie + w$count_tv_show)),] 

plot_ly(w, x = w$country, y = ~count_movie, 
        type = 'bar', name = 'Movie', marker = list(color = '#bd3939')) %>% 
  add_trace(y = ~count_tv_show, name = 'TV Show', marker = list(color = '#399ba3')) %>% 
  layout(xaxis = list(categoryorder = "array", 
                      categoryarray = w$country, 
                      title = "Улс"), 
         yaxis = list(title = 'Өгөгдлийн тоо'),
         barmode = 'stack', 
         title = "Үйлдвэрлэсэн агуулгын хэмжээгээр эхний 12 улс", margin = list(t = 54),
         legend = list(x = 100, y = 0.5)) 

4.3 Жилийн болгоны агуулгын өсөлт

df_by_date_full <- df %>% group_by(date_added) %>% 
  summarise(added_today = n()) %>% 
  mutate(total_number_of_content = cumsum(added_today), type = "Total")

df_by_date <- df %>% group_by(date_added, type) %>% 
  summarise(added_today = n()) %>% 
  ungroup() %>% 
  group_by(type) %>%
  mutate(total_number_of_content = cumsum(added_today))
`summarise()` has grouped output by 'date_added'. You can override using the `.groups` argument.
full_data <- rbind(as.data.frame(df_by_date_full), as.data.frame(df_by_date))

plot_ly(full_data, x = ~date_added, y = ~total_number_of_content, 
        mode = 'lines', type = 'scatter',
        color = ~type, colors = c("#bd3939",  "#9addbd", "#399ba3")) %>% 
  layout(yaxis = list(title = 'Тоо'), 
         xaxis = list(title = 'он'), 
         title = "Жилийн болгоны агуулгын өсөлт", margin = list(t = 54),
         legend = list(x = 100, y = 0.5))

4.4 Сард нэмэгдсэн агуулгын хэмжээ

df_by_date_month <- df %>% group_by(month_added = floor_date(date_added, "month"), type) %>%
  summarise(added_today = n())
`summarise()` has grouped output by 'month_added'. You can override using the `.groups` argument.
wd <- reshape(data = data.frame(df_by_date_month),
              idvar = "month_added",
              v.names = "added_today",
              timevar = "type",
              direction = "wide")

names(wd)[2] <- "added_today_movie"
names(wd)[3] <- "added_today_tv_show"
wd$added_today_movie[is.na(wd$added_today_movie)] <- 0
wd$added_today_tv_show[is.na(wd$added_today_tv_show)] <- 0
wd <-na.omit(wd)

plot_ly(wd, x = wd$month_added, y = ~added_today_movie, 
        type = 'bar', name = 'Movie', 
        marker = list(color = '#bd3939')) %>% 
  add_trace(y = ~added_today_tv_show, 
            name = 'TV Show', 
            marker = list(color = '#399ba3')) %>% 
  layout(xaxis = list(categoryorder = 'array', 
                      categoryarray = wd$month_added, 
                      title = 'Он'), 
         yaxis = list(title = 'Тоо'), 
         barmode = 'stack', 
         title = "Сард нэмэгдсэн агуулгын хэмжээ", margin = list(t = 54),
         legend = list(x = 100, y = 0.5))

4.5 Үнэлгээгээр агуулгын хуваарилалт

df_by_rating <- df %>% group_by(rating) %>% 
  summarise(count = n())

plot_ly(df_by_rating, type = 'pie',
        labels = ~rating, values = ~count) %>% 
  layout(xaxis = list(showgrid = F, zeroline = F, showticklabels = F),
         yaxis = list(showgrid = F, zeroline = F, showticklabels = F),
         title = "Үнэлгээгээр агуулгын хуваарилалт", margin = list(t = 54),
         legend = list(x = 100, y = 0.5))

4.6 Шилдэг төрлүүд (Кино болон ТВ шоу)

s_genres <- strsplit(df$listed_in, split = ", ")
genres_listed_in <- data.frame(type = rep(df$type, sapply(s_genres, length)), 
                               listed_in = unlist(s_genres))
genres_listed_in$listed_in <- as.character(gsub(",","",genres_listed_in$listed_in))

df_by_listed_in <- genres_listed_in %>% 
  group_by(type, listed_in) %>% 
  summarise(count = n()) %>% 
  arrange(desc(count)) %>% top_n(10)
`summarise()` has grouped output by 'type'. You can override using the `.groups` argument.Selecting by count
plot_ly(df_by_listed_in, x = ~listed_in, y = ~count,
        type = 'bar', color = ~type,
        colors = c("#bd3939", "#399ba3")) %>%
  layout(xaxis = list(categoryorder = "array", 
                      categoryarray = df_by_listed_in$listed_in, 
                      title = 'Төрөл',
                      tickangle = 45), 
         yaxis = list(title = 'Тоо хэмжээ'), 
         title = "Шилдэг төрлүүд (Кино болон ТВ шоу)", margin = list(t = 54),
         legend = list(x = 100, y = 0.5))

4.7 Шилдэг 12 орны киноны үргэлжлэх хугацаа


mov_duration_cntry <- na.omit(df[df$type == "Movie",][,c("country", "duration")])

s_dur <- strsplit(mov_duration_cntry$country, split = ", ")
duration_full <- data.frame(duration = rep(mov_duration_cntry$duration,
                                           sapply(s_dur, length)),
                            country = unlist(s_dur))
duration_full$duration <- as.numeric(gsub(" min","", duration_full$duration))

duration_full_subset <- duration_full[duration_full$country %in% 
                                        c("United States", "India", "United Kingdom",
                                          "Canada", "France", "Japan", "Spain", "South Korea",
                                          "Mexico", "Australia", "China", "Taiwan"),]

plot_ly(duration_full_subset, y = ~duration, color = ~country, type = "box") %>% 
  layout(xaxis = list(title = "Улс"), 
         yaxis = list(title = 'Хугацаа (минутаар)'),
         title = "Шилдэг 12 орны киноны үргэлжлэх хугацаа", margin = list(t = 54),
         legend = list(x = 100, y = 0.5))
Warning: n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning: n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning: n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning: n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors

4.8 Ангилалуудыг харуулах: Корреляци ба хамгийн түгээмэл

df_show_categories <- df %>% 
                        select(c('show_id','type','listed_in')) %>% 
                        separate_rows(listed_in, sep = ',') %>%
                        rename(Show_Category = listed_in)
df_show_categories$Show_Category <- trimws(df_show_categories$Show_Category)
head(df_show_categories)
NA

df_show_categories %>% mutate(Show_Category = fct_infreq(Show_Category)) %>% 
        ggplot(aes(x = Show_Category)) + 
            geom_bar() + scale_x_discrete() + facet_wrap(~type, scales = 'free_x')  +  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) + coord_cartesian(xlim = c(1,20))

df_unique_categories <- df_show_categories %>% group_by(type,Show_Category) %>%  summarise()
`summarise()` has grouped output by 'type'. You can override using the `.groups` argument.
df_category_correlations_movies <- data.frame(expand_grid(type = 'Movie', 
                                             Category1 = subset(df_unique_categories, type == 'Movie')$Show_Category,
                                             Category2 = subset(df_unique_categories, type == 'Movie')$Show_Category))
                                  
df_category_correlations_TV <-      data.frame(expand_grid(type = 'TV Show', 
                                             Category1 = subset(df_unique_categories, type == 'TV Show')$Show_Category,
                                             Category2 = subset(df_unique_categories, type == 'TV Show')$Show_Category))
                                 
df_category_correlations <- rbind(df_category_correlations_movies,df_category_correlations_TV)
df_category_correlations$matched_count <- apply(df_category_correlations, MARGIN = 1,FUN = function(x) {
                                            length(intersect(subset(df_show_categories, type == x['type'] & Show_Category == x['Category1'])$show_id,
                                            subset(df_show_categories, type == x['type'] & Show_Category == x['Category2'])$show_id))})

df_category_correlations <- subset(df_category_correlations, (as.character(Category1) < as.character(Category2)) & (matched_count > 0))
# Change plot size to 8 x 3
options(repr.plot.width=14, repr.plot.height=10)

ggplot(subset(df_category_correlations, type == 'Movie'), aes(x = Category1, y = Category2, fill = matched_count)) + 
  geom_tile() + facet_wrap( ~type, scales = 'free')  + scale_fill_distiller(palette = "Spectral") + 
            theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.text = element_text(size = 14), legend.title = element_text(size = 16))

ggplot(subset(df_category_correlations, type == 'TV Show'), aes(x = Category1, y = Category2, fill = matched_count)) + 
        geom_tile() + facet_wrap( ~type, scales = 'free') +  scale_fill_distiller(palette = "Spectral") + 
            theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), , legend.text = element_text(size = 14), legend.title = element_text(size = 16))

4.9 Жүжигчидтэй холбоотой өгөгдөл

df %>% select(c('show_id','cast','director')) %>% 
        gather(key = 'role', value = 'person', cast, director) %>% 
             filter(person != "") %>% separate_rows(person, sep = ',') -> df_show_people

df_show_people$person <- trimws(df_show_people$person)
head(df_show_people)
df_people_freq<- df_show_people %>% group_by(person,role) %>% 
                    summarise(count = n()) %>% arrange(desc(count))
`summarise()` has grouped output by 'person'. You can override using the `.groups` argument.
df_people_freq %>% group_by(role) %>% top_n(10,count) %>% ungroup() %>% ggplot(aes(x = fct_reorder(person,count,.desc = T), y = count, fill = role)) + 
            geom_bar(stat = 'identity') + scale_x_discrete() + facet_wrap(~role, scales = 'free_x')  + theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),legend.position = 'none') + labs(x = 'жүжигчин болон зохиолчдын нэрс')

LS0tCnRpdGxlOiAibmV0ZmxpeCDQuNC50L0g0LTQsNGC0LAg0LDQvdCw0LvQuNGC0LjQuiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgMS4g0KXRjdGA0Y3Qs9GC0Y3QuSDRgdCw0L3Qs9GD0YPQtDoKCmBgYHtyfQpwYWNrYWdlcyA9IGMoJ3RpZHl2ZXJzZScsICdrYWJsZUV4dHJhJywgJ3Bsb3RseScsICdsdWJyaWRhdGUnLCAncGFjbWFuJykKCmZvciAocCBpbiBwYWNrYWdlcyl7CiAgaWYgKCFyZXF1aXJlKHAsY2hhcmFjdGVyLm9ubHkgPSBUKSl7CiAgICBpbnN0YWxsLnBhY2thZ2VzKHApCiAgfQogIGxpYnJhcnkocCxjaGFyYWN0ZXIub25seSA9IFQpCn0KcF9sb2FkKHRpZHl2ZXJzZSxsdWJyaWRhdGUsc2hvd3RleHQpCnNob3d0ZXh0X2F1dG8oKQpmb250X2FkZF9nb29nbGUoIkJlYmFzIE5ldWUiLCAiQmViYXMgTmV1ZSIpCmBgYAoKIyMgMi4g06jQs9Op0LPQtNOp0Lsg0YPQvdGI0LjQtiDQsNCy0LDRhToKCmBgYHtyfQpkZiA8LSByZWFkX2NzdignZGF0YXNldC9uZXRmbGl4X3RpdGxlcy5jc3YnKQpgYGAKCiMjIDMuINOo0LPTqdCz0LTTqdC7INCx0L7Qu9C+0LLRgdGA0YPRg9C70LDQu9GCCgozLjEg06jQs9Op0LPQtNOp0Lsg0LHQsNCz0YHQs9Cw0LvRggoKYGBge3J9CiMg0KXRjdGA0Y3Qs9GG0Y3RjdCz0q/QuSDRg9GC0LPRg9GD0LTRi9CzINGG0Y3QstGN0YDQu9GN0YUg0Y/QstGGCmRmIDwtIHRpYmJsZTo6YXNfdGliYmxlKGRmKSAlPiUgCiAgc2VsZWN0KC1jKCBkZXNjcmlwdGlvbikpCmBgYAoKYGBge3J9CiMg0LTQsNGC0LAg0YjQsNC70YLQs9Cw0LvRggprYWJsZShkZlsxOjEwLF0pICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiNTAwcHgiKQpgYGAKCjMuMiDQpdC+0L7RgdC+0L0g0YPRgtCz0YPRg9C00YvQsyDRhtGN0LLRjdGA0LvRjdGFLCDRhtGN0LPRhtC70Y3RhQoKYGBge3J9CiMg0KXQvtC+0YHQvtC9INGD0YLQs9Cw0YLQsNC5INOp0LPTqdCz0LTQu9C40LnQsyDQuNC70YDSr9Kv0LvRjdGFCmRhdGEuZnJhbWUodmFyID0gYyhjb2xuYW1lcyhkZikpLCAKICAgICAgICAgICBtaXNzaW5nID0gc2FwcGx5KGRmLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKSwgcm93Lm5hbWVzID0gTlVMTCkgJT4lCiAgbXV0YXRlKG1pc3NpbmcgPSBjZWxsX3NwZWMobWlzc2luZywgImh0bWwiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGlmZWxzZShtaXNzaW5nID4gMCwgJ3JlZCcsICdibGFjaycpKSkgJT4lIAogIHJlbmFtZShg0JHQsNCz0LDQvdGL0L0g0L3RjdGAYCA9IHZhciwgYNCl0L7QvtGB0L7QvSDRg9GC0LPRi9C9INGC0L7QvmAgPSBtaXNzaW5nKSAlPiUKICBrYWJsZShmb3JtYXQgPSAiaHRtbCIsIGVzY2FwZSA9IEYsIGFsaWduID0gYygibCIsICJjIikpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLCBmdWxsX3dpZHRoID0gRikKYGBgCgpgYGB7cn0KIyDQnNC+0LQg0L7Qu9C+0YUg0YTRg9C90LrRhwpnZXRtb2RlIDwtIGZ1bmN0aW9uKHYpIHsKICAgdW5pcXYgPC0gdW5pcXVlKHYpCiAgIHVuaXF2W3doaWNoLm1heCh0YWJ1bGF0ZShtYXRjaCh2LCB1bmlxdikpKV0KfQpkZiRyYXRpbmdbaXMubmEoZGYkcmF0aW5nKV0gPC0gZ2V0bW9kZShkZiRyYXRpbmcpCgojINC00LDQstGF0LDRgNC00YHQsNC9INOp0LPTqdCz0LTTqdC70q/Sr9C00LjQudCzINGG0Y3QstGN0YXQu9GN0YUgLT4gdGl0bGUsIGNvdW50cnksIHR5cGUg0LHQvtC70L7QvSByZWxlYXNlX3llYXIKZGYgPC0gZGlzdGluY3QoZGYsIHR5cGUsIHRpdGxlLCBjb3VudHJ5LCByZWxlYXNlX3llYXIsIHNob3dfaWQsIGxpc3RlZF9pbiwgLmtlZXBfYWxsID0gVCkKYGBgCgozLjMg0J7QvSDRgdCw0YDRi9C9INC/0L7RgNC80LDRgtGL0L0g06nTqdGA0YfQu9Op0LvRggoKYGBge3J9CiMg0L7QvSDRgdCw0YDRi9C9INGD0YLQs9GL0L0g0L/QvtGA0LzQsNGC0YvQvSDTqdOp0YDRh9C706nQu9GCCmRmJGRhdGVfYWRkZWQgPC0gYXMuRGF0ZShkZiRkYXRlX2FkZGVkLCBmb3JtYXQgPSAiJUIgJWQsICVZIikKYGBgCgpgYGB7cn0KIyDQvtC9INGB0LDRgNGL0L0g0L/QvtGA0LzQsNGC0YvQvSDRiNCw0LvQs9Cw0LvRggprYWJsZShkZlsxOjEwLF0pICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAlPiUgCiAgY29sdW1uX3NwZWMoNiwgY29sb3IgPSAncmVkJywgYm9sZCA9IFQpICU+JSAKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMzUycHgiKQpgYGAKIyMgNC4g0JTSr9GA0YHQu9GN0YUg0Y3RhtGB0LjQudC9INCw0LvRhdCw0LzRg9GD0LQg0LHQsCDQvtC50LvQs9C+0LvRgtGD0YPQtAoKCjQuMSDQkNCz0YPRg9C70LPRi9C9INGC06nRgNC706nTqdGAINGN0LfQu9GN0YUg0YXRg9Cy0YwKCmBgYHtyfQpjb250ZW50X2J5X3R5cGUgPC0gZGYgJT4lIGdyb3VwX2J5KHR5cGUpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpCgpwbG90X2x5KGNvbnRlbnRfYnlfdHlwZSwgbGFiZWxzID0gfnR5cGUsIHZhbHVlcyA9IH5jb3VudCwgCiAgICAgICAgdHlwZSA9ICdwaWUnLCBtYXJrZXIgPSBsaXN0KGNvbG9ycyA9IGMoIiNiZDM5MzkiLCAiIzM5OWJhMyIpKSkgJT4lIAogIGxheW91dCh4YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGLCB6ZXJvbGluZSA9IEYsIHNob3d0aWNrbGFiZWxzID0gRiksCiAgICAgICAgIHlheGlzID0gbGlzdChzaG93Z3JpZCA9IEYsIHplcm9saW5lID0gRiwgc2hvd3RpY2tsYWJlbHMgPSBGKSwKICAgICAgICAgdGl0bGUgPSAi0JDQs9GD0YPQu9Cz0YvQvSDRgtOp0YDQu9Op06nRgCDRjdC30LvRjdGFINGF0YPQstGMIiwgbWFyZ2luID0gbGlzdCh0ID0gNTQpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHggPSAxMDAsIHkgPSAwLjUpKQpgYGAKCgo0LjIg0q7QudC70LTQstGN0YDQu9GN0YHRjdC9INCw0LPRg9GD0LvQs9GL0L0g0YXRjdC80LbRjdGN0LPRjdGN0YAg0Y3RhdC90LjQuSAxMiDRg9C70YEKYGBge3J9CgpzIDwtIHN0cnNwbGl0KGRmJGNvdW50cnksIHNwbGl0ID0gIiwgIikKY250cnlfc3BsaXQgPC0gZGF0YS5mcmFtZSh0eXBlID0gcmVwKGRmJHR5cGUsIHNhcHBseShzLCBsZW5ndGgpKSwgY291bnRyeSA9IHVubGlzdChzKSkKY250cnlfc3BsaXQkY291bnRyeSA8LSBhcy5jaGFyYWN0ZXIoZ3N1YigiLCIsIiIsIGNudHJ5X3NwbGl0JGNvdW50cnkpKQoKYW1vdW50X2J5X2NvdW50cnkgPC0gbmEub21pdChjbnRyeV9zcGxpdCkgJT4lCiAgZ3JvdXBfYnkoY291bnRyeSwgdHlwZSkgJT4lCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQoKdyA8LSByZXNoYXBlKGRhdGEgPSBkYXRhLmZyYW1lKGFtb3VudF9ieV9jb3VudHJ5KSwgCiAgICAgICAgICAgICBpZHZhciA9ICJjb3VudHJ5IiwKICAgICAgICAgICAgIHYubmFtZXMgPSAiY291bnQiLAogICAgICAgICAgICAgdGltZXZhciA9ICJ0eXBlIiwKICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJ3aWRlIikgJT4lIAogIGFycmFuZ2UoZGVzYyhjb3VudC5Nb3ZpZSkpICU+JSB0b3BfbigxMikKCm5hbWVzKHcpWzJdIDwtICJjb3VudF9tb3ZpZSIKbmFtZXModylbM10gPC0gImNvdW50X3R2X3Nob3ciCncgPC0gd1tvcmRlcihkZXNjKHckY291bnRfbW92aWUgKyB3JGNvdW50X3R2X3Nob3cpKSxdIAoKcGxvdF9seSh3LCB4ID0gdyRjb3VudHJ5LCB5ID0gfmNvdW50X21vdmllLCAKICAgICAgICB0eXBlID0gJ2JhcicsIG5hbWUgPSAnTW92aWUnLCBtYXJrZXIgPSBsaXN0KGNvbG9yID0gJyNiZDM5MzknKSkgJT4lIAogIGFkZF90cmFjZSh5ID0gfmNvdW50X3R2X3Nob3csIG5hbWUgPSAnVFYgU2hvdycsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAnIzM5OWJhMycpKSAlPiUgCiAgbGF5b3V0KHhheGlzID0gbGlzdChjYXRlZ29yeW9yZGVyID0gImFycmF5IiwgCiAgICAgICAgICAgICAgICAgICAgICBjYXRlZ29yeWFycmF5ID0gdyRjb3VudHJ5LCAKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gItCj0LvRgSIpLCAKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ9Oo0LPTqdCz0LTQu9C40LnQvSDRgtC+0L4nKSwKICAgICAgICAgYmFybW9kZSA9ICdzdGFjaycsIAogICAgICAgICB0aXRsZSA9ICLSrtC50LvQtNCy0Y3RgNC70Y3RgdGN0L0g0LDQs9GD0YPQu9Cz0YvQvSDRhdGN0LzQttGN0Y3Qs9GN0Y3RgCDRjdGF0L3QuNC5IDEyINGD0LvRgSIsIG1hcmdpbiA9IGxpc3QodCA9IDU0KSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh4ID0gMTAwLCB5ID0gMC41KSkgCmBgYAoKNC4zINCW0LjQu9C40LnQvSDQsdC+0LvQs9C+0L3RiyDQsNCz0YPRg9C70LPRi9C9INOp0YHTqdC70YIKYGBge3J9CmRmX2J5X2RhdGVfZnVsbCA8LSBkZiAlPiUgZ3JvdXBfYnkoZGF0ZV9hZGRlZCkgJT4lIAogIHN1bW1hcmlzZShhZGRlZF90b2RheSA9IG4oKSkgJT4lIAogIG11dGF0ZSh0b3RhbF9udW1iZXJfb2ZfY29udGVudCA9IGN1bXN1bShhZGRlZF90b2RheSksIHR5cGUgPSAiVG90YWwiKQoKZGZfYnlfZGF0ZSA8LSBkZiAlPiUgZ3JvdXBfYnkoZGF0ZV9hZGRlZCwgdHlwZSkgJT4lIAogIHN1bW1hcmlzZShhZGRlZF90b2RheSA9IG4oKSkgJT4lIAogIHVuZ3JvdXAoKSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lCiAgbXV0YXRlKHRvdGFsX251bWJlcl9vZl9jb250ZW50ID0gY3Vtc3VtKGFkZGVkX3RvZGF5KSkKCmZ1bGxfZGF0YSA8LSByYmluZChhcy5kYXRhLmZyYW1lKGRmX2J5X2RhdGVfZnVsbCksIGFzLmRhdGEuZnJhbWUoZGZfYnlfZGF0ZSkpCgpwbG90X2x5KGZ1bGxfZGF0YSwgeCA9IH5kYXRlX2FkZGVkLCB5ID0gfnRvdGFsX251bWJlcl9vZl9jb250ZW50LCAKICAgICAgICBtb2RlID0gJ2xpbmVzJywgdHlwZSA9ICdzY2F0dGVyJywKICAgICAgICBjb2xvciA9IH50eXBlLCBjb2xvcnMgPSBjKCIjYmQzOTM5IiwgICIjOWFkZGJkIiwgIiMzOTliYTMiKSkgJT4lIAogIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAn0KLQvtC+JyksIAogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAn0L7QvScpLCAKICAgICAgICAgdGl0bGUgPSAi0JbQuNC70LjQudC9INCx0L7Qu9Cz0L7QvdGLINCw0LPRg9GD0LvQs9GL0L0g06nRgdOp0LvRgiIsIG1hcmdpbiA9IGxpc3QodCA9IDU0KSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh4ID0gMTAwLCB5ID0gMC41KSkKYGBgCgo0LjQg0KHQsNGA0LQg0L3RjdC80Y3Qs9C00YHRjdC9INCw0LPRg9GD0LvQs9GL0L0g0YXRjdC80LbRjdGNCmBgYHtyfQpkZl9ieV9kYXRlX21vbnRoIDwtIGRmICU+JSBncm91cF9ieShtb250aF9hZGRlZCA9IGZsb29yX2RhdGUoZGF0ZV9hZGRlZCwgIm1vbnRoIiksIHR5cGUpICU+JQogIHN1bW1hcmlzZShhZGRlZF90b2RheSA9IG4oKSkKCndkIDwtIHJlc2hhcGUoZGF0YSA9IGRhdGEuZnJhbWUoZGZfYnlfZGF0ZV9tb250aCksCiAgICAgICAgICAgICAgaWR2YXIgPSAibW9udGhfYWRkZWQiLAogICAgICAgICAgICAgIHYubmFtZXMgPSAiYWRkZWRfdG9kYXkiLAogICAgICAgICAgICAgIHRpbWV2YXIgPSAidHlwZSIsCiAgICAgICAgICAgICAgZGlyZWN0aW9uID0gIndpZGUiKQoKbmFtZXMod2QpWzJdIDwtICJhZGRlZF90b2RheV9tb3ZpZSIKbmFtZXMod2QpWzNdIDwtICJhZGRlZF90b2RheV90dl9zaG93Igp3ZCRhZGRlZF90b2RheV9tb3ZpZVtpcy5uYSh3ZCRhZGRlZF90b2RheV9tb3ZpZSldIDwtIDAKd2QkYWRkZWRfdG9kYXlfdHZfc2hvd1tpcy5uYSh3ZCRhZGRlZF90b2RheV90dl9zaG93KV0gPC0gMAp3ZCA8LW5hLm9taXQod2QpCgpwbG90X2x5KHdkLCB4ID0gd2QkbW9udGhfYWRkZWQsIHkgPSB+YWRkZWRfdG9kYXlfbW92aWUsIAogICAgICAgIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdNb3ZpZScsIAogICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSAnI2JkMzkzOScpKSAlPiUgCiAgYWRkX3RyYWNlKHkgPSB+YWRkZWRfdG9kYXlfdHZfc2hvdywgCiAgICAgICAgICAgIG5hbWUgPSAnVFYgU2hvdycsIAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gJyMzOTliYTMnKSkgJT4lIAogIGxheW91dCh4YXhpcyA9IGxpc3QoY2F0ZWdvcnlvcmRlciA9ICdhcnJheScsIAogICAgICAgICAgICAgICAgICAgICAgY2F0ZWdvcnlhcnJheSA9IHdkJG1vbnRoX2FkZGVkLCAKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gJ9Ce0L0nKSwgCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICfQotC+0L4nKSwgCiAgICAgICAgIGJhcm1vZGUgPSAnc3RhY2snLCAKICAgICAgICAgdGl0bGUgPSAi0KHQsNGA0LQg0L3RjdC80Y3Qs9C00YHRjdC9INCw0LPRg9GD0LvQs9GL0L0g0YXRjdC80LbRjdGNIiwgbWFyZ2luID0gbGlzdCh0ID0gNTQpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KHggPSAxMDAsIHkgPSAwLjUpKQpgYGAKCjQuNSDSrtC90Y3Qu9Cz0Y3RjdCz0Y3RjdGAINCw0LPRg9GD0LvQs9GL0L0g0YXRg9Cy0LDQsNGA0LjQu9Cw0LvRggpgYGB7cn0KZGZfYnlfcmF0aW5nIDwtIGRmICU+JSBncm91cF9ieShyYXRpbmcpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpCgpwbG90X2x5KGRmX2J5X3JhdGluZywgdHlwZSA9ICdwaWUnLAogICAgICAgIGxhYmVscyA9IH5yYXRpbmcsIHZhbHVlcyA9IH5jb3VudCkgJT4lIAogIGxheW91dCh4YXhpcyA9IGxpc3Qoc2hvd2dyaWQgPSBGLCB6ZXJvbGluZSA9IEYsIHNob3d0aWNrbGFiZWxzID0gRiksCiAgICAgICAgIHlheGlzID0gbGlzdChzaG93Z3JpZCA9IEYsIHplcm9saW5lID0gRiwgc2hvd3RpY2tsYWJlbHMgPSBGKSwKICAgICAgICAgdGl0bGUgPSAi0q7QvdGN0LvQs9GN0Y3Qs9GN0Y3RgCDQsNCz0YPRg9C70LPRi9C9INGF0YPQstCw0LDRgNC40LvQsNC70YIiLCBtYXJnaW4gPSBsaXN0KHQgPSA1NCksCiAgICAgICAgIGxlZ2VuZCA9IGxpc3QoeCA9IDEwMCwgeSA9IDAuNSkpCmBgYAoKCgo0LjYg0KjQuNC70LTRjdCzINGC06nRgNC70q/Sr9C0ICjQmtC40L3QviDQsdC+0LvQvtC9INCi0JIg0YjQvtGDKQpgYGB7cn0Kc19nZW5yZXMgPC0gc3Ryc3BsaXQoZGYkbGlzdGVkX2luLCBzcGxpdCA9ICIsICIpCmdlbnJlc19saXN0ZWRfaW4gPC0gZGF0YS5mcmFtZSh0eXBlID0gcmVwKGRmJHR5cGUsIHNhcHBseShzX2dlbnJlcywgbGVuZ3RoKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGlzdGVkX2luID0gdW5saXN0KHNfZ2VucmVzKSkKZ2VucmVzX2xpc3RlZF9pbiRsaXN0ZWRfaW4gPC0gYXMuY2hhcmFjdGVyKGdzdWIoIiwiLCIiLGdlbnJlc19saXN0ZWRfaW4kbGlzdGVkX2luKSkKCmRmX2J5X2xpc3RlZF9pbiA8LSBnZW5yZXNfbGlzdGVkX2luICU+JSAKICBncm91cF9ieSh0eXBlLCBsaXN0ZWRfaW4pICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBhcnJhbmdlKGRlc2MoY291bnQpKSAlPiUgdG9wX24oMTApCgpwbG90X2x5KGRmX2J5X2xpc3RlZF9pbiwgeCA9IH5saXN0ZWRfaW4sIHkgPSB+Y291bnQsCiAgICAgICAgdHlwZSA9ICdiYXInLCBjb2xvciA9IH50eXBlLAogICAgICAgIGNvbG9ycyA9IGMoIiNiZDM5MzkiLCAiIzM5OWJhMyIpKSAlPiUKICBsYXlvdXQoeGF4aXMgPSBsaXN0KGNhdGVnb3J5b3JkZXIgPSAiYXJyYXkiLCAKICAgICAgICAgICAgICAgICAgICAgIGNhdGVnb3J5YXJyYXkgPSBkZl9ieV9saXN0ZWRfaW4kbGlzdGVkX2luLCAKICAgICAgICAgICAgICAgICAgICAgIHRpdGxlID0gJ9Ci06nRgNOp0LsnLAogICAgICAgICAgICAgICAgICAgICAgdGlja2FuZ2xlID0gNDUpLCAKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ9Ci0L7QviDRhdGN0LzQttGN0Y0nKSwgCiAgICAgICAgIHRpdGxlID0gItCo0LjQu9C00Y3QsyDRgtOp0YDQu9Kv0q/QtCAo0JrQuNC90L4g0LHQvtC70L7QvSDQotCSINGI0L7RgykiLCBtYXJnaW4gPSBsaXN0KHQgPSA1NCksCiAgICAgICAgIGxlZ2VuZCA9IGxpc3QoeCA9IDEwMCwgeSA9IDAuNSkpCmBgYAoKCjQuNyDQqNC40LvQtNGN0LMgMTIg0L7RgNC90Ysg0LrQuNC90L7QvdGLINKv0YDQs9GN0LvQttC70Y3RhSDRhdGD0LPQsNGG0LDQsApgYGB7cn0KCm1vdl9kdXJhdGlvbl9jbnRyeSA8LSBuYS5vbWl0KGRmW2RmJHR5cGUgPT0gIk1vdmllIixdWyxjKCJjb3VudHJ5IiwgImR1cmF0aW9uIildKQoKc19kdXIgPC0gc3Ryc3BsaXQobW92X2R1cmF0aW9uX2NudHJ5JGNvdW50cnksIHNwbGl0ID0gIiwgIikKZHVyYXRpb25fZnVsbCA8LSBkYXRhLmZyYW1lKGR1cmF0aW9uID0gcmVwKG1vdl9kdXJhdGlvbl9jbnRyeSRkdXJhdGlvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNhcHBseShzX2R1ciwgbGVuZ3RoKSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3VudHJ5ID0gdW5saXN0KHNfZHVyKSkKZHVyYXRpb25fZnVsbCRkdXJhdGlvbiA8LSBhcy5udW1lcmljKGdzdWIoIiBtaW4iLCIiLCBkdXJhdGlvbl9mdWxsJGR1cmF0aW9uKSkKCmR1cmF0aW9uX2Z1bGxfc3Vic2V0IDwtIGR1cmF0aW9uX2Z1bGxbZHVyYXRpb25fZnVsbCRjb3VudHJ5ICVpbiUgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJVbml0ZWQgU3RhdGVzIiwgIkluZGlhIiwgIlVuaXRlZCBLaW5nZG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkNhbmFkYSIsICJGcmFuY2UiLCAiSmFwYW4iLCAiU3BhaW4iLCAiU291dGggS29yZWEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWV4aWNvIiwgIkF1c3RyYWxpYSIsICJDaGluYSIsICJUYWl3YW4iKSxdCgpwbG90X2x5KGR1cmF0aW9uX2Z1bGxfc3Vic2V0LCB5ID0gfmR1cmF0aW9uLCBjb2xvciA9IH5jb3VudHJ5LCB0eXBlID0gImJveCIpICU+JSAKICBsYXlvdXQoeGF4aXMgPSBsaXN0KHRpdGxlID0gItCj0LvRgSIpLCAKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gJ9Cl0YPQs9Cw0YbQsNCwICjQvNC40L3Rg9GC0LDQsNGAKScpLAogICAgICAgICB0aXRsZSA9ICLQqNC40LvQtNGN0LMgMTIg0L7RgNC90Ysg0LrQuNC90L7QvdGLINKv0YDQs9GN0LvQttC70Y3RhSDRhdGD0LPQsNGG0LDQsCIsIG1hcmdpbiA9IGxpc3QodCA9IDU0KSwKICAgICAgICAgbGVnZW5kID0gbGlzdCh4ID0gMTAwLCB5ID0gMC41KSkKYGBgCgoKNC44INCQ0L3Qs9C40LvQsNC70YPRg9C00YvQsyDRhdCw0YDRg9GD0LvQsNGFOiDQmtC+0YDRgNC10LvRj9GG0Lgg0LHQsCDRhdCw0LzQs9C40LnQvSDRgtKv0LPRjdGN0LzRjdC7CgpgYGB7cn0KZGZfc2hvd19jYXRlZ29yaWVzIDwtIGRmICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGMoJ3Nob3dfaWQnLCd0eXBlJywnbGlzdGVkX2luJykpICU+JSAKICAgICAgICAgICAgICAgICAgICAgICAgc2VwYXJhdGVfcm93cyhsaXN0ZWRfaW4sIHNlcCA9ICcsJykgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgIHJlbmFtZShTaG93X0NhdGVnb3J5ID0gbGlzdGVkX2luKQpkZl9zaG93X2NhdGVnb3JpZXMkU2hvd19DYXRlZ29yeSA8LSB0cmltd3MoZGZfc2hvd19jYXRlZ29yaWVzJFNob3dfQ2F0ZWdvcnkpCmhlYWQoZGZfc2hvd19jYXRlZ29yaWVzKQoKYGBgCgpgYGB7cn0KCmRmX3Nob3dfY2F0ZWdvcmllcyAlPiUgbXV0YXRlKFNob3dfQ2F0ZWdvcnkgPSBmY3RfaW5mcmVxKFNob3dfQ2F0ZWdvcnkpKSAlPiUgCiAgICAgICAgZ2dwbG90KGFlcyh4ID0gU2hvd19DYXRlZ29yeSkpICsgCiAgICAgICAgICAgIGdlb21fYmFyKCkgKyBzY2FsZV94X2Rpc2NyZXRlKCkgKyBmYWNldF93cmFwKH50eXBlLCBzY2FsZXMgPSAnZnJlZV94JykgICsgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSkgKyBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMSwyMCkpCmBgYAoKYGBge3J9CmRmX3VuaXF1ZV9jYXRlZ29yaWVzIDwtIGRmX3Nob3dfY2F0ZWdvcmllcyAlPiUgZ3JvdXBfYnkodHlwZSxTaG93X0NhdGVnb3J5KSAlPiUgIHN1bW1hcmlzZSgpCmRmX2NhdGVnb3J5X2NvcnJlbGF0aW9uc19tb3ZpZXMgPC0gZGF0YS5mcmFtZShleHBhbmRfZ3JpZCh0eXBlID0gJ01vdmllJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENhdGVnb3J5MSA9IHN1YnNldChkZl91bmlxdWVfY2F0ZWdvcmllcywgdHlwZSA9PSAnTW92aWUnKSRTaG93X0NhdGVnb3J5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDYXRlZ29yeTIgPSBzdWJzZXQoZGZfdW5pcXVlX2NhdGVnb3JpZXMsIHR5cGUgPT0gJ01vdmllJykkU2hvd19DYXRlZ29yeSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKZGZfY2F0ZWdvcnlfY29ycmVsYXRpb25zX1RWIDwtICAgICAgZGF0YS5mcmFtZShleHBhbmRfZ3JpZCh0eXBlID0gJ1RWIFNob3cnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2F0ZWdvcnkxID0gc3Vic2V0KGRmX3VuaXF1ZV9jYXRlZ29yaWVzLCB0eXBlID09ICdUViBTaG93JykkU2hvd19DYXRlZ29yeSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ2F0ZWdvcnkyID0gc3Vic2V0KGRmX3VuaXF1ZV9jYXRlZ29yaWVzLCB0eXBlID09ICdUViBTaG93JykkU2hvd19DYXRlZ29yeSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIApkZl9jYXRlZ29yeV9jb3JyZWxhdGlvbnMgPC0gcmJpbmQoZGZfY2F0ZWdvcnlfY29ycmVsYXRpb25zX21vdmllcyxkZl9jYXRlZ29yeV9jb3JyZWxhdGlvbnNfVFYpCmRmX2NhdGVnb3J5X2NvcnJlbGF0aW9ucyRtYXRjaGVkX2NvdW50IDwtIGFwcGx5KGRmX2NhdGVnb3J5X2NvcnJlbGF0aW9ucywgTUFSR0lOID0gMSxGVU4gPSBmdW5jdGlvbih4KSB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVuZ3RoKGludGVyc2VjdChzdWJzZXQoZGZfc2hvd19jYXRlZ29yaWVzLCB0eXBlID09IHhbJ3R5cGUnXSAmIFNob3dfQ2F0ZWdvcnkgPT0geFsnQ2F0ZWdvcnkxJ10pJHNob3dfaWQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Vic2V0KGRmX3Nob3dfY2F0ZWdvcmllcywgdHlwZSA9PSB4Wyd0eXBlJ10gJiBTaG93X0NhdGVnb3J5ID09IHhbJ0NhdGVnb3J5MiddKSRzaG93X2lkKSl9KQoKZGZfY2F0ZWdvcnlfY29ycmVsYXRpb25zIDwtIHN1YnNldChkZl9jYXRlZ29yeV9jb3JyZWxhdGlvbnMsIChhcy5jaGFyYWN0ZXIoQ2F0ZWdvcnkxKSA8IGFzLmNoYXJhY3RlcihDYXRlZ29yeTIpKSAmIChtYXRjaGVkX2NvdW50ID4gMCkpCiMgOCB4IDMg0YXRjdC80LbRjdGNCm9wdGlvbnMocmVwci5wbG90LndpZHRoPTE0LCByZXByLnBsb3QuaGVpZ2h0PTEwKQoKZ2dwbG90KHN1YnNldChkZl9jYXRlZ29yeV9jb3JyZWxhdGlvbnMsIHR5cGUgPT0gJ01vdmllJyksIGFlcyh4ID0gQ2F0ZWdvcnkxLCB5ID0gQ2F0ZWdvcnkyLCBmaWxsID0gbWF0Y2hlZF9jb3VudCkpICsgCiAgZ2VvbV90aWxlKCkgKyBmYWNldF93cmFwKCB+dHlwZSwgc2NhbGVzID0gJ2ZyZWUnKSAgKyBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlNwZWN0cmFsIikgKyAKICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoc3Vic2V0KGRmX2NhdGVnb3J5X2NvcnJlbGF0aW9ucywgdHlwZSA9PSAnVFYgU2hvdycpLCBhZXMoeCA9IENhdGVnb3J5MSwgeSA9IENhdGVnb3J5MiwgZmlsbCA9IG1hdGNoZWRfY291bnQpKSArIAogICAgICAgIGdlb21fdGlsZSgpICsgZmFjZXRfd3JhcCggfnR5cGUsIHNjYWxlcyA9ICdmcmVlJykgKyAgc2NhbGVfZmlsbF9kaXN0aWxsZXIocGFsZXR0ZSA9ICJTcGVjdHJhbCIpICsgCiAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSAsIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQpgYGAKNC45INCW0q/QttC40LPRh9C40LTRgtGN0Lkg0YXQvtC70LHQvtC+0YLQvtC5INOp0LPTqdCz0LTTqdC7CgpgYGB7cn0KZGYgJT4lIHNlbGVjdChjKCdzaG93X2lkJywnY2FzdCcsJ2RpcmVjdG9yJykpICU+JSAKICAgICAgICBnYXRoZXIoa2V5ID0gJ3JvbGUnLCB2YWx1ZSA9ICdwZXJzb24nLCBjYXN0LCBkaXJlY3RvcikgJT4lIAogICAgICAgICAgICAgZmlsdGVyKHBlcnNvbiAhPSAiIikgJT4lIHNlcGFyYXRlX3Jvd3MocGVyc29uLCBzZXAgPSAnLCcpIC0+IGRmX3Nob3dfcGVvcGxlCgpkZl9zaG93X3Blb3BsZSRwZXJzb24gPC0gdHJpbXdzKGRmX3Nob3dfcGVvcGxlJHBlcnNvbikKaGVhZChkZl9zaG93X3Blb3BsZSkKYGBgCgpgYGB7cn0KZGZfcGVvcGxlX2ZyZXE8LSBkZl9zaG93X3Blb3BsZSAlPiUgZ3JvdXBfYnkocGVyc29uLHJvbGUpICU+JSAKICAgICAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSBhcnJhbmdlKGRlc2MoY291bnQpKQoKZGZfcGVvcGxlX2ZyZXEgJT4lIGdyb3VwX2J5KHJvbGUpICU+JSB0b3BfbigxMCxjb3VudCkgJT4lIHVuZ3JvdXAoKSAlPiUgZ2dwbG90KGFlcyh4ID0gZmN0X3Jlb3JkZXIocGVyc29uLGNvdW50LC5kZXNjID0gVCksIHkgPSBjb3VudCwgZmlsbCA9IHJvbGUpKSArIAogICAgICAgICAgICBnZW9tX2JhcihzdGF0ID0gJ2lkZW50aXR5JykgKyBzY2FsZV94X2Rpc2NyZXRlKCkgKyBmYWNldF93cmFwKH5yb2xlLCBzY2FsZXMgPSAnZnJlZV94JykgICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLGxlZ2VuZC5wb3NpdGlvbiA9ICdub25lJykgKyBsYWJzKHggPSAn0LbSr9C20LjQs9GH0LjQvSDQsdC+0LvQvtC9INC30L7RhdC40L7Qu9GH0LTRi9C9INC90Y3RgNGBJykKYGBgCgo=